package jpa;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import net.vidageek.mirror.dsl.Mirror;
import net.vidageek.mirror.get.dsl.GetterHandler;
import net.vidageek.mirror.list.dsl.MirrorList;
import net.vidageek.mirror.set.dsl.SetterHandler;

public class BaseDao<T> {
    private String persistClassName;
    private String shortClassName;
    private EntityManager em = null;
    private java.util.logging.Logger logger;
    static private List<String> ignoreFields = new ArrayList<String>();
    static {
        String[] words = {"READ_WRITE_OK", "LOAD_REQUIRED", "READ_OK", "CHECK_READ", "MEDIATE_READ", "CHECK_WRITE", "MEDIATE_WRITE", "SERIALIZABLE"};
        for (String word : words){
            ignoreFields.add(word);
        }
    }
    public BaseDao(){
        this.persistClassName = ((Class<T>) ((ParameterizedType) (getClass().getGenericSuperclass())).getActualTypeArguments()[0]).getName();
        this.shortClassName = this.persistClassName.substring(this.persistClassName.lastIndexOf(".")+1);
        em = EMFService.get().createEntityManager();
        logger = java.util.logging.Logger.getAnonymousLogger();
    }
    public void insert(T obj){
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            em.persist(obj);
            tx.commit();
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
    }
    public void update(T obj){
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            em.persist(obj);
            tx.commit();
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
    }
    public void delete(T obj){
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            em.remove(obj);
            tx.commit();
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }
    }
    public List<T> list(){
        List<T> objs = null;
        
        javax.persistence.Query q = em.createQuery("select t from " + this.shortClassName + " t");
        objs = new ArrayList<T>(q.getResultList());
 
        return objs;
    }
    public T get(String id){
        ArrayList<T> objs = null;
        javax.persistence.Query q = em.createQuery("select t from " + this.shortClassName + " t where id=" + id);
        objs = new ArrayList<T>(q.getResultList());
        if (objs != null && objs.size() > 0){
            return objs.get(0);
        }
        return null;
    }
    public List<T> find(T sc, String orderBy){
        ArrayList<T> objs = null;
        String pSql = "select t from " + this.shortClassName + " t where ";
        GetterHandler getterHandler = new Mirror().on(sc).get();
        
        MirrorList<Field> fields = null;
        try {
            fields = new Mirror().on(Class.forName(persistClassName)).reflectAll().fields();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        
        boolean isFirst = true;
        for (Field field : fields){
            if (field.getName().startsWith("jdo") || BaseDao.ignoreFields.contains(field.getName())){
                continue;
            }
            Object val = getterHandler.field(field);
            if (val != null){
                if (!isFirst){
                    pSql += "and ";
                }else{
                    isFirst = false;
                }
                if (field.getType().getName().equals(String.class.getName())){
                    pSql += field.getName() + "='" + (String)val + "' ";
                }else{
                    pSql += field.getName() + "=" + val + " ";
                }
            }
        }
        if (orderBy != null && !orderBy.equals("")){
            pSql += " order by " + orderBy;
        }
        System.out.println("find: "+pSql);
        javax.persistence.Query q = em.createQuery( pSql );
        objs = new ArrayList<T>(q.getResultList());
        logger.log(Level.INFO, "resultList size: " + objs.size());
        return objs;
    }
}
